// ValidationAspects
// Written by Mike Saunders
// Released under Microsoft Public License (Ms-PL)
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using NUnit.Framework;
using ValidationAspects.Core;

namespace TestValidationAspects.Core
{
	[TestFixture]
	public class TestTypeExtensions
	{
		[Test]
		[ExpectedException(typeof(ArgumentNullException))]
		public void Test_GetAllProperties_throws_for_null_param()
		{
			TypeExtensions.GetAllProperties(null).Count();
		}

		[Test]
		public void Test_GetAllProperties_returns_empty_enumerable_for_type_with_no_properties()
		{
			Assert.AreEqual(0, typeof(NoProperties).GetAllProperties().Count());
		}

		[Test]
		public void Test_GetAllProperties()
		{
			List<PropertyInfo> infos = typeof(Dummy).GetAllProperties().ToList();
			Assert.AreEqual(27, infos.Count);

			List<string> propertyNames = infos.Select(pi => pi.Name).ToList();

			Assert.IsTrue(propertyNames.Contains("AbstractBasePublicGetPublicSet"));
			Assert.IsTrue(propertyNames.Contains("AbstractBasePublicGetProtectedSet"));
			Assert.IsTrue(propertyNames.Contains("AbstractBasePublicGetPrivateSet"));
			Assert.IsTrue(propertyNames.Contains("AbstractBaseProtectedGetProtectedSet"));
			Assert.IsTrue(propertyNames.Contains("AbstractBaseProtectedGetPrivateSet"));
			Assert.IsTrue(propertyNames.Contains("AbstractBasePrivateGetPrivateSet"));
			Assert.IsTrue(propertyNames.Contains("AbstractBaseStaticPrivateGetPrivateSet"));
			Assert.IsTrue(propertyNames.Contains("AbstractBasePublicGet"));
			Assert.IsTrue(propertyNames.Contains("AbstractBasePublicSet"));
			Assert.IsTrue(propertyNames.Contains("VirtualPublicGetPublicSet"));

			Assert.IsTrue(propertyNames.Contains("ConcreteBasePublicGetPublicSet"));
			Assert.IsTrue(propertyNames.Contains("ConcreteBasePublicGetProtectedSet"));
			Assert.IsTrue(propertyNames.Contains("ConcreteBasePublicGetPrivateSet"));
			Assert.IsTrue(propertyNames.Contains("ConcreteBaseProtectedGetProtectedSet"));
			Assert.IsTrue(propertyNames.Contains("ConcreteBaseProtectedGetPrivateSet"));
			Assert.IsTrue(propertyNames.Contains("ConcreteBasePrivateGetPrivateSet"));
			Assert.IsTrue(propertyNames.Contains("ConcreteBasePublicGet"));
			Assert.IsTrue(propertyNames.Contains("ConcreteBasePublicSet"));

			Assert.IsTrue(propertyNames.Contains("ComponentPublicGetPublicSet"));
			Assert.IsTrue(propertyNames.Contains("ComponentPublicGetProtectedSet"));
			Assert.IsTrue(propertyNames.Contains("ComponentPublicGetPrivateSet"));
			Assert.IsTrue(propertyNames.Contains("ComponentProtectedGetProtectedSet"));
			Assert.IsTrue(propertyNames.Contains("ComponentProtectedGetPrivateSet"));
			Assert.IsTrue(propertyNames.Contains("ComponentPrivateGetPrivateSet"));
			Assert.IsTrue(propertyNames.Contains("ComponentPublicGet"));
			Assert.IsTrue(propertyNames.Contains("ComponentPublicSet"));
			Assert.IsTrue(propertyNames.Contains("VirtualPublicGetPublicSet"));
		}

		#region Mocks
		public abstract class AbstractBase
		{
			public bool AbstractBasePublicGetPublicSet { get; set; }

			public bool AbstractBasePublicGetProtectedSet { get; protected set; }

			public bool AbstractBasePublicGetPrivateSet { get; private set; }

			protected bool AbstractBaseProtectedGetProtectedSet { get; set; }

			protected bool AbstractBaseProtectedGetPrivateSet { get; set; }

			private bool AbstractBasePrivateGetPrivateSet { get; set; }

			private static bool AbstractBaseStaticPrivateGetPrivateSet { get; set; }

			public bool AbstractBasePublicGet
			{
				get { return true; }
			}

			public bool AbstractBasePublicSet
			{
				set { }
			}

			public virtual bool VirtualPublicGetPublicSet { get; set; }
		}

		public class ConcreteBase : AbstractBase
		{
			public bool ConcreteBasePublicGetPublicSet { get; set; }

			public bool ConcreteBasePublicGetProtectedSet { get; protected set; }

			public bool ConcreteBasePublicGetPrivateSet { get; private set; }

			protected bool ConcreteBaseProtectedGetProtectedSet { get; set; }

			protected bool ConcreteBaseProtectedGetPrivateSet { get; set; }

			private bool ConcreteBasePrivateGetPrivateSet { get; set; }

			public bool ConcreteBasePublicGet
			{
				get { return true; }
			}

			public bool ConcreteBasePublicSet
			{
				set { }
			}
		}

		public class Dummy : ConcreteBase
		{
			public bool ComponentPublicGetPublicSet { get; set; }

			public bool ComponentPublicGetProtectedSet { get; protected set; }

			public bool ComponentPublicGetPrivateSet { get; private set; }

			protected bool ComponentProtectedGetProtectedSet { get; set; }

			protected bool ComponentProtectedGetPrivateSet { get; set; }

			private bool ComponentPrivateGetPrivateSet { get; set; }

			public bool ComponentPublicGet
			{
				get { return true; }
			}

			public bool ComponentPublicSet
			{
				set { }
			}

			public override bool VirtualPublicGetPublicSet { get; set; }
		}

		public class NoProperties {}
		#endregion
	}
}